home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / debug.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-14  |  13.9 KB  |  643 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993,1994 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* MiNT debugging output routines */
  8. /* also, ksprintf is put here, for lack of any better place to put it */
  9.  
  10. #include "mint.h"
  11. #include <stdarg.h>
  12.  
  13. static void VDEBUGOUT P_((int, const char *, va_list));
  14. int vksprintf(char *buf, const char *fmt, va_list args);
  15.  
  16. /*
  17.  * ksprintf implements a very crude sprintf() function that provides only
  18.  * what MiNT needs...
  19.  *
  20.  * NOTE: this sprintf probably doesn't conform to any standard at
  21.  * all. It's only use in life is that it won't overflow fixed
  22.  * size buffers (i.e. it won't try to write more than SPRINTF_MAX
  23.  * characters into a string)
  24.  */
  25.  
  26. static int
  27. PUTC(char *p, int c, int *cnt, int width) {
  28.     int put = 1;
  29.  
  30.     if (*cnt <= 0) return 0;
  31.     *p++ = c;
  32.     *cnt -= 1;
  33.     while (*cnt > 0 && --width > 0) {
  34.         *p++ = ' ';
  35.         *cnt -= 1;
  36.         put++;
  37.     }
  38.     return put;
  39. }
  40.  
  41. static int
  42. PUTS(char *p, const char *s, int *cnt, int width) {
  43.     int put = 0;
  44.  
  45.     if (s == 0) s = "(null)";
  46.  
  47.     while (*cnt > 0 && *s) {
  48.         *p++ = *s++;
  49.         put++;
  50.         *cnt -= 1;
  51.         width--;
  52.     }
  53.     while (width-- > 0 && *cnt > 0) {
  54.         *p++ = ' ';
  55.         put++;
  56.         *cnt -= 1;
  57.     }
  58.     return put;
  59. }
  60.  
  61. static int
  62. PUTL(char *p, unsigned long u, int base, int *cnt, int width, int fill_char)
  63. {
  64.     int put = 0;
  65.     static char obuf[32];
  66.     char *t;
  67.  
  68.     t = obuf;
  69.  
  70.     do {
  71.         *t++ = "0123456789ABCDEF"[u % base];
  72.         u /= base;
  73.         width--;
  74.     } while (u > 0);
  75.  
  76.     while (width-- > 0 && *cnt > 0) {
  77.         *p++ = fill_char;
  78.         put++;
  79.         *cnt -= 1;
  80.     }
  81.     while (*cnt > 0 && t != obuf) {
  82.         *p++ = *--t;
  83.         put++;
  84.         *cnt -= 1;
  85.     }
  86.     return put;
  87. }
  88.  
  89. int
  90. vksprintf(char *buf, const char *fmt, va_list args)
  91. {
  92.     char *p = buf, c, fill_char;
  93.     char *s_arg;
  94.     int i_arg;
  95.     long l_arg;
  96.     int cnt;
  97.     int width, long_flag;
  98.  
  99.     cnt = SPRINTF_MAX - 1;
  100.     while( (c = *fmt++) != 0 ) {
  101.         if (c != '%') {
  102.             p += PUTC(p, c, &cnt, 1);
  103.             continue;
  104.         }
  105.         c = *fmt++;
  106.         width = 0;
  107.         long_flag = 0;
  108.         fill_char = ' ';
  109.         if (c == '0') fill_char = '0';
  110.         while (c && isdigit(c)) {
  111.             width = 10*width + (c-'0');
  112.             c = *fmt++;
  113.         }
  114.         if (c == 'l' || c == 'L') {
  115.             long_flag = 1;
  116.             c = *fmt++;
  117.         }
  118.         if (!c) break;
  119.  
  120.         switch (c) {
  121.         case '%':
  122.             p += PUTC(p, c, &cnt, width);
  123.             break;
  124.         case 'c':
  125.             i_arg = va_arg(args, int);
  126.             p += PUTC(p, i_arg, &cnt, width);
  127.             break;
  128.         case 's':
  129.             s_arg = va_arg(args, char *);
  130.             p += PUTS(p, s_arg, &cnt, width);
  131.             break;
  132.         case 'd':
  133.             if (long_flag) {
  134.                 l_arg = va_arg(args, long);
  135.             } else {
  136.                 l_arg = va_arg(args, int);
  137.             }
  138.             if (l_arg < 0) {
  139.                 p += PUTC(p, '-', &cnt, 1);
  140.                 width--;
  141.                 l_arg = -l_arg;
  142.             }
  143.             p += PUTL(p, l_arg, 10, &cnt, width, fill_char);
  144.             break;
  145.         case 'o':
  146.             if (long_flag) {
  147.                 l_arg = va_arg(args, long);
  148.             } else {
  149.                 l_arg = va_arg(args, unsigned int);
  150.             }
  151.             p += PUTL(p, l_arg, 8, &cnt, width, fill_char);
  152.             break;
  153.         case 'x':
  154.             if (long_flag) {
  155.                 l_arg = va_arg(args, long);
  156.             } else {
  157.                 l_arg = va_arg(args, unsigned int);
  158.             }
  159.             p += PUTL(p, l_arg, 16, &cnt, width, fill_char);
  160.             break;
  161.         case 'u':
  162.             if (long_flag) {
  163.                 l_arg = va_arg(args, long);
  164.             } else {
  165.                 l_arg = va_arg(args, unsigned int);
  166.             }
  167.             p += PUTL(p, l_arg, 10, &cnt, width, fill_char);
  168.             break;
  169.  
  170.         }
  171.     }
  172.     *p = 0;
  173.     return (int)(p - buf);
  174. }
  175.  
  176. int ARGS_ON_STACK 
  177. ksprintf(char *buf, const char *fmt, ...)
  178. {
  179.     va_list args;
  180.     int foo;
  181.  
  182.     va_start(args, fmt);
  183.     foo = vksprintf(buf, fmt, args);    
  184.     va_end(args);
  185.     return foo;
  186. }
  187.  
  188. int debug_level = 1;    /* how much debugging info should we print? */
  189. int out_device = 2;    /* BIOS device to write errors to */
  190.  
  191. /*
  192.  * out_next[i] is the out_device value to use when the current
  193.  * device is i and the user hits F3.
  194.  * Cycle is CON -> PRN -> AUX -> MIDI -> 6 -> 7 -> 8 -> 9 -> CON
  195.  * (Note: BIOS devices 6-8 exist on Mega STe and TT, 9 on TT.)
  196.  *
  197.  * out_device and this table are exported to bios.c and used here in HALT().
  198.  */
  199.  
  200. /*            0  1  2  3  4  5  6  7  8  9 */
  201. char out_next[] = { 1, 3, 0, 6, 0, 0, 7, 8, 9, 2 };
  202.  
  203. /*
  204.  * debug log modes:
  205.  *
  206.  * 0: no logging.
  207.  * 1: log all messages, dump the log any time something happens at
  208.  *    a level that gets shown.  Thus, if you're at debug_level 2,
  209.  *    everything is logged, and if something at levels 1 or 2 happens,
  210.  *    the log is dumped.
  211.  *
  212.  * LB_LINE_LEN is 20 greater than SPRINTF_MAX because up to 20 bytes
  213.  * are prepended to the buffer string passed to ksprintf.
  214.  */
  215.  
  216. #define LBSIZE 50                /* number of lines */
  217. #define LB_LINE_LEN (SPRINTF_MAX+20)        /* width of a line */
  218. int debug_logging;
  219. int logptr;
  220. static char logbuf[LBSIZE][LB_LINE_LEN];
  221. static short logtime[LBSIZE];    /* low 16 bits of 200Hz: timestamp of msg */
  222.  
  223. /*
  224.  * Extra terse settings - don't even output ALERTs unless asked to.
  225.  *
  226.  * Things that happen in on an idle Desktop are at LOW_LEVEL:
  227.  * Psemaphore, Pmsg, Syield.
  228.  */
  229. #if 0    /* now in debug.h */
  230. #define FORCE_LEVEL 0
  231. #define ALERT_LEVEL 1
  232. #define DEBUG_LEVEL 2
  233. #define TRACE_LEVEL 3
  234. #define LOW_LEVEL 4
  235. #endif
  236.  
  237. /*
  238.  * The inner loop does this: at each newline, the keyboard is polled. If
  239.  * you've hit a key, then it's checked: if it's ctl-alt, do_func_key is
  240.  * called to do what it says, and that's that.  If not, then you pause the
  241.  * output.  If you now hit a ctl-alt key, it gets done and you're still
  242.  * paused.  Only hitting a non-ctl-alt key will get you out of the pause. 
  243.  * (And only a non-ctl-alt key got you into it, too!)
  244.  *
  245.  * When out_device isn't the screen, number keys give you the same effects
  246.  * as function keys.  The only way to get into this code, however, is to
  247.  * have something produce debug output in the first place!  This is
  248.  * awkward: Hit a key on out_device, then hit ctl-alt-F5 on the console so
  249.  * bios.c will call DUMPPROC, which will call ALERT, which will call this.
  250.  * It'll see the key you hit on out_device and drop you into this loop.
  251.  * CTL-ALT keys make BIOS call do_func_key even when out_device isn't the
  252.  * console.
  253.  */
  254.  
  255. void
  256. debug_ws(s)
  257.     const char *s;
  258. {
  259.     long key;
  260.     int scan;
  261.     int stopped;
  262.  
  263.     while (*s) {
  264.     (void)Bconout(out_device, *s);
  265.     while (*s == '\n' && out_device != 0 && Bconstat(out_device)) {
  266.         stopped = 0;
  267.         while (1) {
  268.         if (out_device == 2) {
  269.         /* got a key; if ctl-alt then do it */
  270.             if ((Kbshift(-1) & 0x0c) == 0x0c) {
  271.             key = Bconin(out_device);
  272.             scan = (int) (((key >> 16) & 0xff));
  273.             do_func_key(scan);
  274.             goto ptoggle;
  275.             }
  276.             else goto cont;
  277.         }
  278.         else {
  279.             key = Bconin(out_device);
  280.             if (key < '0' || key > '9') {
  281. ptoggle:        /* not a func key */
  282.             if (stopped) break;
  283.             else stopped = 1;
  284.             }
  285.             else {
  286.             /* digit key from debug device == Fn */
  287.             if (key == '0') scan = 0x44;
  288.             else scan = (int) (key - '0' + 0x3a);
  289.             do_func_key(scan);
  290.             }
  291.         }
  292.         }
  293.     }
  294. cont:
  295.     s++;
  296.     }
  297. }
  298.  
  299. /*
  300.  * _ALERT(s) returns 1 for success and 0 for failure.
  301.  * It attempts to write the string to "the alert pipe," u:\pipe\alert.
  302.  * If the write fails because the pipe is full, we "succeed" anyway.
  303.  *
  304.  * This is called in vdebugout and also in memprot.c for memory violations.
  305.  * It's also used by the Salert() system call in dos.c.
  306.  */
  307.  
  308. int
  309. _ALERT(s)
  310. char *s;
  311. {
  312.     FILEPTR *f;
  313.     char alertbuf[SPRINTF_MAX+10], *ptr, *lastspace;
  314.     int counter;
  315.     char *alert;
  316.     int olddebug = debug_level;
  317.     int oldlogging = debug_logging;
  318.  
  319. /* temporarily reduce the debug level, so errors finding
  320.  * u:\pipe\alert don't get reported
  321.  */
  322.     debug_level = debug_logging = 0;
  323.     f = do_open("u:\\pipe\\alert",(O_WRONLY | O_NDELAY),0,(XATTR *)0);
  324.     debug_level = olddebug;
  325.     debug_logging = oldlogging;
  326.  
  327.     if (f) {
  328. /*
  329.  * format the string into an alert box
  330.  */
  331.     if (*s == '[') {    /* already an alert */
  332.         alert = s;
  333.     } else {
  334.         alert = alertbuf;
  335.         ksprintf(alertbuf, "[1][%s", s);
  336. /*
  337.  * make sure no lines exceed 30 characters; also, filter out any
  338.  * reserved characters like '[' or ']'
  339.  */
  340.         ptr = alertbuf+4;
  341.         counter = 0;
  342.         lastspace = 0;
  343.         while(*ptr) {
  344.             if (*ptr == ' ') {
  345.                 lastspace = ptr;
  346.             } else if (*ptr == '[') {
  347.                 *ptr = '(';
  348.             } else if (*ptr == ']') {
  349.                 *ptr = ')';
  350.             } else if (*ptr == '|') {
  351.                 *ptr = ':';
  352.             }
  353.             if (counter++ >= 29) {
  354.                 if (lastspace) {
  355.                     *lastspace = '|';
  356.                     counter = (int) (ptr - lastspace);
  357.                     lastspace = 0;
  358.                 } else {
  359.                     *ptr = '|';
  360.                     counter = 0;
  361.                 }
  362.             }
  363.             ptr++;
  364.         }
  365.         strcpy(ptr, "][  OK  ]");
  366.     }
  367.  
  368.     (*f->dev->write)(f,alert,(long)strlen(alert)+1);
  369.     do_close(f);
  370.     return 1;
  371.     }
  372.     else return 0;
  373. }
  374.  
  375. static void
  376. VDEBUGOUT(level, s, args)
  377.     int level;
  378.     const char *s;
  379.     va_list args;
  380. {
  381.     char *lp;
  382.     char *lptemp;
  383.  
  384.     logtime[logptr] = (short)(*(long *)0x4baL);
  385.     lp = logbuf[logptr];
  386.     if (++logptr == LBSIZE) logptr = 0;
  387.  
  388.     if (curproc) {
  389.         ksprintf(lp,"pid %3d (%s): ", curproc->pid, curproc->name);
  390.         lptemp = lp+strlen(lp);
  391.     }
  392.     else {
  393.         lptemp = lp;
  394.     }
  395.  
  396.     vksprintf(lptemp, s, args);
  397.  
  398.     /* for alerts, try the alert pipe unconditionally */
  399.     if (level == ALERT_LEVEL && _ALERT(lp)) return;
  400.  
  401.     if (debug_level >= level) {
  402.         debug_ws(lp);
  403.         debug_ws("\r\n");
  404.     }
  405. }
  406.  
  407. void ARGS_ON_STACK Tracelow(const char *s, ...)
  408. {
  409.     va_list args;
  410.  
  411.     if (debug_logging || (debug_level >= LOW_LEVEL)) {
  412.         va_start(args, s);
  413.         VDEBUGOUT(LOW_LEVEL, s, args);
  414.         va_end(args);
  415.     }
  416. }
  417.  
  418. void ARGS_ON_STACK Trace(const char *s, ...)
  419. {
  420.     va_list args;
  421.  
  422.     if (debug_logging || (debug_level >= TRACE_LEVEL)) {
  423.         va_start(args, s);
  424.         VDEBUGOUT(TRACE_LEVEL, s, args);
  425.         va_end(args);
  426.     }
  427. }
  428.  
  429. void ARGS_ON_STACK Debug(const char *s, ...)
  430. {
  431.     va_list args;
  432.  
  433.     if (debug_logging || (debug_level >= DEBUG_LEVEL)) {
  434.         va_start(args, s);
  435.         VDEBUGOUT(DEBUG_LEVEL, s, args);
  436.         va_end(args);
  437.     }
  438.     if (debug_logging && debug_level >= DEBUG_LEVEL) DUMPLOG();
  439. }
  440.  
  441. void ARGS_ON_STACK ALERT(const char *s, ...)
  442. {
  443.     va_list args;
  444.  
  445.     if (debug_logging || debug_level >= ALERT_LEVEL) {
  446.         va_start(args, s);
  447.         VDEBUGOUT(ALERT_LEVEL, s, args);
  448.         va_end(args);
  449.     }
  450.     if (debug_logging && debug_level >= ALERT_LEVEL) DUMPLOG();
  451. }
  452.  
  453. void ARGS_ON_STACK FORCE(const char *s, ...)
  454. {
  455.     va_list args;
  456.  
  457.     va_start(args, s);
  458.     VDEBUGOUT(FORCE_LEVEL, s, args);
  459.     va_end(args);
  460.     /* don't dump log here - hardly ever what you mean to do. */
  461. }
  462.  
  463. void
  464. DUMPLOG()
  465. {
  466.     char *end;
  467.     char *start;
  468.     short *timeptr;
  469.     char timebuf[6];
  470.  
  471.     /* logbuf[logptr] is the oldest string here */
  472.  
  473.     end = start = logbuf[logptr];
  474.     timeptr = &logtime[logptr];
  475.  
  476.     do {
  477.         if (*start) {
  478.         ksprintf(timebuf,"%04x ",*timeptr);
  479.         debug_ws(timebuf);
  480.         debug_ws(start);
  481.         debug_ws("\r\n");
  482.         *start = '\0';
  483.         }
  484.         start += LB_LINE_LEN;
  485.         timeptr++;
  486. #ifdef LATTICE
  487. #pragma ignore 83    /* [reference beyond object size] */
  488. #endif
  489.         if (start == logbuf[LBSIZE]) {
  490. #ifdef LATTICE
  491. #pragma warning 83    /* [reference beyond object size] */
  492. #endif
  493.         start = logbuf[0];
  494.         timeptr = &logtime[0];
  495.         }
  496.         } while (start != end);
  497.  
  498.         logptr = 0;
  499. }
  500.  
  501. /* wait for a key to be pressed */
  502. void
  503. PAUSE()
  504. {
  505.     debug_ws("Hit a key\r\n");
  506.     (void)Bconin(2);
  507. }
  508.   
  509. EXITING
  510. void ARGS_ON_STACK FATAL(const char *s, ...)
  511. {
  512.     va_list args;
  513.  
  514.     va_start(args, s);
  515.     VDEBUGOUT(-1, s, args);
  516.     va_end(args);
  517.     if (debug_logging) {
  518.         DUMPLOG();
  519.     }
  520.  
  521.     HALT();
  522. }
  523.  
  524.  
  525. static const char *rebootmsg[MAXLANG] = {
  526. "FATAL ERROR. You must reboot the system.\r\n",
  527. "FATALER FEHLER. Das System muâ‚§ neu gestartet werden.\r\n",    /* German */
  528. "FATAL ERROR. You must reboot the system.\r\n",        /* French */
  529. "FATAL ERROR. You must reboot the system.\r\n",        /* UK */
  530. "FATAL ERROR. You must reboot the system.\r\n",        /* Spanish */
  531. "FATAL ERROR. You must reboot the system.\r\n"        /* Italian */
  532. };
  533.  
  534. EXITING 
  535. void HALT()
  536. {
  537.     long r;
  538.     long key;
  539.     int scan;
  540.     extern long tosssp;    /* in main.c */
  541. #ifdef PROFILING
  542.     extern EXITING _exit P_((int)) NORETURN;
  543. #endif
  544.     restr_intr();    /* restore interrupts to normal */
  545. #ifdef DEBUG_INFO
  546.     debug_ws("Fatal MiNT error: adjust debug level and hit a key...\r\n");
  547. #else
  548.     debug_ws(rebootmsg[gl_lang]);
  549. #endif
  550.     sys_q[READY_Q] = 0;    /* prevent context switches */
  551.  
  552.     for(;;) {
  553.         /* get a key; if ctl-alt then do it, else halt */
  554.         key = Bconin(out_device);
  555.         if ((key & 0x0c000000L) == 0x0c000000L) {
  556.             scan = (int) ((key >> 16) & 0xff);
  557.             do_func_key(scan);
  558.         }
  559.         else {
  560.             break;
  561.         }
  562.     }
  563.     for(;;) {
  564.         debug_ws(rebootmsg[gl_lang]);
  565.         r = Bconin(2);
  566.  
  567.         if ( (r & 0x0ff) == 'x' ) {
  568.             extern int no_mem_prot;
  569.             close_filesys();
  570.             if (!no_mem_prot)
  571.                 restr_mmu();
  572.             restr_screen();
  573.             (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  574. #ifdef PROFILING
  575.             _exit(0);
  576. #else
  577.             Pterm0();
  578. #endif
  579.         }
  580.     }
  581. }
  582.  
  583.  
  584. /* some key definitions */
  585. #define CTRLALT 0xc
  586. #define DEL 0x53    /* scan code of delete key */
  587. #define UNDO 0x61    /* scan code of undo key */
  588.  
  589. void
  590. do_func_key(scan)
  591.     int scan;
  592. {
  593.     extern struct tty con_tty;
  594.  
  595.     switch (scan) {
  596.     case DEL:
  597.         reboot();
  598.         break;
  599.     case UNDO:
  600.         killgroup(con_tty.pgrp, SIGQUIT, 1);
  601.         break;
  602. #ifdef DEBUG_INFO
  603.     case 0x3b:        /* F1: increase debugging level */
  604.         debug_level++;
  605.         break;
  606.     case 0x3c:        /* F2: reduce debugging level */
  607.         if (debug_level > 0)
  608.             --debug_level;
  609.         break;
  610.     case 0x3d:        /* F3: cycle out_device */
  611.         out_device = out_next[out_device];
  612.         break;
  613.     case 0x3e:        /* F4: set out_device to console */
  614.         out_device = 2;
  615.         break;
  616.     case 0x3f:        /* F5: dump memory */
  617.         DUMP_ALL_MEM();
  618.         break;
  619.     case 0x58:        /* shift+F5: dump kernel allocated memory */
  620.         NALLOC_DUMP();
  621.         break;
  622.     case 0x40:        /* F6: dump processes */
  623.         DUMPPROC();
  624.         break;
  625.     case 0x41:        /* F7: toggle debug_logging */
  626.         debug_logging ^= 1;
  627.         break;
  628.     case 0x42:        /* F8: dump log */
  629.         DUMPLOG();
  630.         break;
  631.     case 0x43:        /* F9: dump the global memory table */
  632.         QUICKDUMP();
  633.         break;
  634.     case 0x5c:        /* shift-F9: dump the mmu tree */
  635.         BIG_MEM_DUMP(1,curproc);
  636.         break;
  637.     case 0x44:        /* F10: do an annotated dump of memory */
  638.         BIG_MEM_DUMP(0,0);
  639.         break;
  640. #endif
  641.     }
  642. }
  643.